package net.cyue.web.easyquery.provider.http.router.spring;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import net.cyue.web.easyquery.core.EasyQueryApplication;
import net.cyue.web.easyquery.core.EasyQueryApplicationTaskType;
import net.cyue.web.easyquery.core.http.HTTPRequestMethod;
import net.cyue.web.easyquery.core.http.adapter.AbstractHTTPRouter;
import net.cyue.web.easyquery.core.http.handler.api.IWebRequestHandler;
import net.cyue.web.easyquery.core.util.TaskUtil;
import net.cyue.web.easyquery.provider.http.servlet.HTTPServletProviderTaskType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.stream.Collectors;

public class SpringHTTPRouter extends AbstractHTTPRouter<ServletContext> {

    private final Logger logger = LoggerFactory.getLogger(this.toString());
    // Spring MVC的请求映射处理器
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    public SpringHTTPRouter(ServletContext context) {
        super(context);
        TaskUtil.Task<WebApplicationContext> setContextTask = (webApplicationContext) -> {
            this.setRequestMappingHandler(webApplicationContext);
            this.runAddRouteTask();
        };
        TaskUtil.Task<EasyQueryApplication<?>> appInitTask = (app) -> {
            ServletContext servletContext = (ServletContext) app.getServerContext();
            WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            setContextTask.run(webApplicationContext);
        };
        TaskUtil.addTask(EasyQueryApplicationTaskType.INIT, appInitTask);
        TaskUtil.addTask(SpringProviderTaskType.SET_CONTEXT, setContextTask);
    }

    public void setRequestMappingHandler(WebApplicationContext webApplicationContext) {
        if (webApplicationContext == null) {
            this.logger.warn("WebApplicationContext 为空");
            return;
        }
        try {
            this.logger.info("获取 RequestMappingHandlerMapping");
            this.requestMappingHandlerMapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class);
        } catch (BeansException e) {
            this.logger.error(e.getMessage());
            // 创建 RequestMappingHandlerMapping
            this.logger.info("自行创建 RequestMappingHandlerMapping");
            this.requestMappingHandlerMapping = new RequestMappingHandlerMapping();
            // 设置ApplicationContext
            this.requestMappingHandlerMapping.setApplicationContext(webApplicationContext);
            // 配置路径匹配器（重要）
            AntPathMatcher pathMatcher = new AntPathMatcher();
            pathMatcher.setCaseSensitive(false); // 忽略URL大小写
            this.requestMappingHandlerMapping.setPathMatcher(pathMatcher);
            // 初始化（关键步骤）
            this.requestMappingHandlerMapping.afterPropertiesSet();

            TaskUtil.addTask(SpringProviderTaskType.SET_BEAN_FACTORY, (beanFactory) -> {
                DefaultListableBeanFactory factory =  (DefaultListableBeanFactory) beanFactory;
                factory.registerSingleton("requestMappingHandlerMapping", this.requestMappingHandlerMapping);
            });
        }
    }
    public void setRequestMappingHandler(RequestMappingHandlerMapping requestMappingHandlerMapping) {
        this.requestMappingHandlerMapping = requestMappingHandlerMapping;
    }

    /**
     * 运行添加路由任务
     */
    private void runAddRouteTask() {
        TaskUtil.runTask(HTTPServletProviderTaskType.ADD_ROUTE, this.context);
    }

    @Override
    public boolean addRoute(String path, IWebRequestHandler handler, HTTPRequestMethod[] methods) {
        // 支持 spring-boot
        if (this.requestMappingHandlerMapping == null) {
            WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.context);
            if (webApplicationContext != null) {
                this.setRequestMappingHandler(webApplicationContext);
            }
        }

        RequestMethod[] springMethods = new RequestMethod[methods.length];
        for (int i = 0; i < springMethods.length; i++) {
            springMethods[i] = RequestMethod.valueOf(methods[i].name());
        }

        TaskUtil.Task<ServletContext> task = (servletContext) -> {
            String newPath = path.trim();
            if (
                servletContext != null &&
                path.startsWith(servletContext.getContextPath())
            ) {
                newPath = path.substring(servletContext.getContextPath().length());
            }

            // 创建请求映射信息
            RequestMappingInfo requestMappingInfo = RequestMappingInfo
                .paths(newPath)
                .methods(springMethods)
                .build();

            try {
                RequestService requestService = new RequestService(handler);
                Method serviceMethod = RequestService.class.getMethod("service", ServletRequest.class, ServletResponse.class);
                this.requestMappingHandlerMapping.registerMapping(
                    requestMappingInfo,
                    requestService,
                    serviceMethod
                );
                this.logger.info(
                    "\n添加路由：\n\t路由: {}\n\t请求方法: {}",
                    path,
                    Arrays.toString(springMethods)
                );
            } catch (NoSuchMethodException e) {
                this.logger.error(e.getMessage());
                throw new RuntimeException(e);
            }
        };

        TaskUtil.addTask(HTTPServletProviderTaskType.ADD_ROUTE, task);
        if (this.requestMappingHandlerMapping == null) {
            return true;
        }
        this.runAddRouteTask();
        return true;
    }
}
